﻿using Caliburn.Micro;
using SD.Infrastructure.WPF.Caliburn.Aspects;
using SD.Infrastructure.WPF.Caliburn.Base;
using SD.IOC.Core.Mediators;
using SlamDunk.MES.Client.ViewModels.Material;
using SlamDunk.MES.IAppService.DTOs.Inputs;
using SlamDunk.MES.IAppService.DTOs.Outputs.PlanContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.ResourceContext;
using SlamDunk.MES.IAppService.Interfaces;
using SlamDunk.MES.Presentation.Maps;
using SlamDunk.MES.Presentation.Models.NotifyModels;
using SlamDunk.ValueObjects.Enums;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel.Extensions;
using System.Threading.Tasks;
using System.Windows;

namespace SlamDunk.MES.Client.ViewModels.ProductionPlan
{
    /// <summary>
    /// 生产计划物料需求视图模型
    /// </summary>
    public class MaterialAskViewModel : ScreenBase
    {
        #region # 字段及构造器

        /// <summary>
        /// 资源定义服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IResourceContract> _resourceContract;

        /// <summary>
        /// 产品定义服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IDefinitionContract> _definitionContact;

        /// <summary>
        /// 计划管理服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IPlanContract> _planContract;

        /// <summary>
        /// 窗口管理器
        /// </summary>
        private readonly IWindowManager _windowManager;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public MaterialAskViewModel(ServiceProxy<IResourceContract> resourceContract, ServiceProxy<IDefinitionContract> definitionContact, ServiceProxy<IPlanContract> planContract, IWindowManager windowManager)
        {
            this._resourceContract = resourceContract;
            this._definitionContact = definitionContact;
            this._planContract = planContract;
            this._windowManager = windowManager;
        }

        #endregion

        #region # 属性

        #region 生产计划 —— ProductionPlanInfo ProductionPlan
        /// <summary>
        /// 生产计划
        /// </summary>
        public ProductionPlanInfo ProductionPlan { get; set; }
        #endregion

        #region 物料需求列表 —— ObservableCollection<PlanMaterialAsk> MaterialAsks
        /// <summary>
        /// 物料需求列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<PlanMaterialAskNm> MaterialAsks { get; set; }
        #endregion

        #endregion

        #region # 方法

        //Initialization

        #region 加载 —— async Task Load(ProductionPlanInfo productionPlan)
        /// <summary>
        /// 加载
        /// </summary>
        /// <param name="productionPlan">生产计划</param>
        public async Task Load(ProductionPlanInfo productionPlan)
        {
            this.ProductionPlan = productionPlan;

            IEnumerable<ProductionMaterialAskInfo> materialAskInfos = await Task.Run(() => this._planContract.Channel.GetProductionMaterialAsks(this.ProductionPlan.Id));
            IEnumerable<PlanMaterialAskNm> materialAsks = materialAskInfos.Select(x => x.ToNotifyView());
            this.MaterialAsks = new ObservableCollection<PlanMaterialAskNm>(materialAsks);
        }
        #endregion


        //Actions

        #region 生成物料需求 —— async void GenerateMaterialAsks()
        /// <summary>
        /// 生成物料需求
        /// </summary>
        public async void GenerateMaterialAsks()
        {
            #region # 验证

            if (this.ProductionPlan.CheckStatus == CheckStatus.Checking)
            {
                MessageBox.Show("当前生产计划正在审核中，不可生成物料需求！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.ProductionPlan.CheckStatus == CheckStatus.Passed)
            {
                MessageBox.Show("当前生产计划已审核通过，不可生成物料需求！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            #endregion

            this.Busy();

            IDictionary<Guid, decimal> materialAskInfos = await Task.Run(() => this._definitionContact.Channel.CalculateMaterialAsks(this.ProductionPlan.BomId,
                this.ProductionPlan.ExpGrossQuantity));
            IDictionary<Guid, MaterialInfo> materialInfos = await Task.Run((() => this._resourceContract.Channel.GetMaterialsById(materialAskInfos.Keys)));

            IList<PlanMaterialAskNm> materialAsks = new List<PlanMaterialAskNm>();
            foreach (KeyValuePair<Guid, decimal> kv in materialAskInfos)
            {
                MaterialInfo materialInfo = materialInfos[kv.Key];
                PlanMaterialAskNm materialAskNm = new PlanMaterialAskNm
                {
                    MaterialId = materialInfo.Id,
                    MaterialNo = materialInfo.Number,
                    MaterialName = materialInfo.Name,
                    Quantity = kv.Value,
                    Unit = materialInfo.StandardUnitNo
                };
                materialAsks.Add(materialAskNm);
            }
            this.MaterialAsks = new ObservableCollection<PlanMaterialAskNm>(materialAsks);

            this.Idle();
        }
        #endregion

        #region 创建物料需求 —— async void CreateMaterialAsk()
        /// <summary>
        /// 创建物料需求
        /// </summary>
        public async void CreateMaterialAsk()
        {
            AddPlanMaterialAskViewModel viewModel = ResolveMediator.Resolve<AddPlanMaterialAskViewModel>();

            this.Busy();
            bool? result = await this._windowManager.ShowDialogAsync(viewModel);
            this.Idle();

            if (result == true)
            {
                PlanMaterialAskNm materialAskNm = this.MaterialAsks.SingleOrDefault(x => x.MaterialId == viewModel.SelectedMaterial.Id);
                if (materialAskNm == null)
                {
                    materialAskNm = new PlanMaterialAskNm
                    {
                        MaterialId = viewModel.SelectedMaterial.Id,
                        MaterialNo = viewModel.SelectedMaterial.Number,
                        MaterialName = viewModel.SelectedMaterial.Name,
                        Quantity = viewModel.Quantity ?? 0,
                        Unit = viewModel.Unit,
                        Description = viewModel.Description
                    };
                    this.MaterialAsks.Add(materialAskNm);
                }
                else
                {
                    materialAskNm.Quantity += viewModel.Quantity ?? 0;
                }
            }
        }
        #endregion

        #region 删除物料需求 —— void RemoveMaterialAsk(PlanMaterialAsk materialAsk)
        /// <summary>
        /// 删除物料需求
        /// </summary>
        /// <param name="materialAskNm">物料需求</param>
        public void RemoveMaterialAsk(PlanMaterialAskNm materialAskNm)
        {
            #region # 验证

            if (this.ProductionPlan.CheckStatus == CheckStatus.Checking)
            {
                MessageBox.Show("当前生产计划正在审核中，不可修改物料需求！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.ProductionPlan.CheckStatus == CheckStatus.Passed)
            {
                MessageBox.Show("当前生产计划已审核通过，不可修改物料需求！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            #endregion

            this.MaterialAsks.Remove(materialAskNm);
        }
        #endregion

        #region 提交 —— async void Submit()
        /// <summary>
        /// 提交
        /// </summary>
        public async void Submit()
        {
            #region # 验证

            if (this.ProductionPlan.CheckStatus == CheckStatus.Checking)
            {
                MessageBox.Show("当前生产计划正在审核中，不可修改物料需求！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.ProductionPlan.CheckStatus == CheckStatus.Passed)
            {
                MessageBox.Show("当前生产计划已审核通过，不可修改物料需求！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            #endregion

            this.Busy();

            IEnumerable<ProductionMaterialAskParam> materialAskParams =
                from materialAsk in this.MaterialAsks
                select new ProductionMaterialAskParam
                {
                    materialId = materialAsk.MaterialId,
                    quantity = materialAsk.Quantity,
                    sort = this.MaterialAsks.IndexOf(materialAsk)
                };

            await Task.Run(() => this._planContract.Channel.SetProductionMaterialAsks(this.ProductionPlan.Id, materialAskParams));

            await base.TryCloseAsync(true);
            this.Idle();
        }
        #endregion

        #endregion
    }
}
